package com.unibeta.vrules.engines.dccimpls.core;

import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.List;
import java.util.Map;

import com.unibeta.vrules.engines.dccimpls.CoreEngine;
import com.unibeta.vrules.engines.dccimpls.RulesInterpreter;
import com.unibeta.vrules.engines.dccimpls.RulesInterpreterFactory;
import com.unibeta.vrules.engines.dccimpls.compiler.MemoryInnerDynamicCompiler;
import com.unibeta.vrules.engines.dccimpls.compiler.MemoryInnerValidationClassLoader;
import com.unibeta.vrules.engines.dccimpls.rules.RulesValidation;
import com.unibeta.vrules.parsers.ConfigurationProxy;
import com.unibeta.vrules.utils.CommonUtils;

public class MemoryInnerCoreEngineImpl extends AbstractCoreEngine implements CoreEngine {

	void interprete(String fileName, String vrulesMode, Class decisionClass) throws Exception {

		if (!ConfigurationProxy.isModified(fileName, decisionClass)) {
			return;
		}

		if (CommonUtils.isNullOrEmpty(vrulesMode)) {
			vrulesMode = ConfigurationProxy.getVRuleSuiteInstance(fileName, decisionClass).getGlobalConfig()
					.isDecisionMode() ? RulesInterpreter.VRULES_ENGINE_MODE_DECISION
							: RulesInterpreter.VRULES_ENGINE_MODE_VALIDATION;
		}

		RulesInterpreter dynamicRulesInterpreter = RulesInterpreterFactory.getInstance(vrulesMode);

		String javaFile = new File(dynamicRulesInterpreter.interprete(fileName, decisionClass)).getPath();
		String result = null;

		try {
			String className = MemoryInnerValidationClassLoader.COM_UNIBETA_VRULES_ENGINES_DCCIMPLS_RULES
					+ CommonUtils.getFileSimpleName(javaFile);
			String JavaSource = new String(Files.readAllBytes(Paths.get(javaFile)));
			
			MemoryInnerValidationClassLoader classLoad = new MemoryInnerValidationClassLoader(className,
					new MemoryInnerDynamicCompiler().compile(CommonUtils.getFileSimpleName(javaFile),
							JavaSource),
					null);
			Object instance = classLoad.newValidationInstance();
			classLoad.offerValidationInstance(instance);
		} catch (Exception e) {
			e.printStackTrace();
			log.error(e.getMessage(), e);
			result = e.getMessage();
		}

		if (result != null) {
			ConfigurationProxy.getModifiedTimeTable().remove(ConfigurationProxy.buildKeyValue(fileName, decisionClass));

			throw new Exception(
					"vRules4j dynamic compiling failed caused by the incorrect configuration, please check the rules configuration file.\nThe invalid file is located in ["
							+ fileName + "], compiling fatal errors were found below:\n" + result);
		} else {
			File srcFile = new File(javaFile);
			srcFile.delete();

			ConfigurationProxy.updateLastModifiedTime(fileName, decisionClass);
		}
	}

	String[] invokeValidate(Object object, String fileName, String entityId, boolean isModified, Class decisionClass)
			throws Exception {

		List<String> ruleIdList = null;
		RulesValidation rulesValidation = null;

		String javaClassName = CommonUtils.generateClassNameByFileFullName(fileName)
				+ RulesInterpreter.JAVA_FILE_SUFFIX;
		String javaFileName = CommonUtils.getFilePathName(fileName) + javaClassName;

		String className = MemoryInnerValidationClassLoader.COM_UNIBETA_VRULES_ENGINES_DCCIMPLS_RULES
				+ CommonUtils.getFileSimpleName(javaFileName);

		MemoryInnerValidationClassLoader validationClassLoader = new MemoryInnerValidationClassLoader(className, null,
				decisionClass);
		Object validator = null;

		if (true || !isModified) {
			validator = validationClassLoader.getValidationInstance();
		}

		if (validator == null) {
			validator = validationClassLoader.newValidationInstance();
		}

		String[] errors = null;

		if (validator instanceof RulesValidation) {
			rulesValidation = (RulesValidation) validator;
		}

		try {
			if (object instanceof Map) {

				Map<String, List<String>> map = ConfigurationProxy.getRulesetMap(fileName, decisionClass);
				errors = rulesValidation.validate((Map) object, map);
			} else {
				errors = rulesValidation.validate(object, entityId,
						ConfigurationProxy.getRulesetMap(fileName, decisionClass));
			}
		} finally {
			validationClassLoader.offerValidationInstance(rulesValidation);
		}

		return errors;
	}
}
